
import os, bpy, bpy.ops, math, mathutils, ossl.util as util, bmesh
from mathutils import Vector
from rna_xml import rna2xml
import xml.etree.ElementTree as ET
from bpy.types import Operator

LLM = None
morphs_to_be_applied = [] # [ "Male_Head", "Male_Torso", "Male_Legs", "Male_Package" ]

Name_to_PNG = {
    "head": "SL-Avatar-Head-1024",
    "upper_body": "SL-Avatar-Upper-1024",
    "lower_body": "SL-Avatar-Lower-1024",
    "eye": "",
    "eyelashes": "",
    "hair": "",
    "skirt": "SL-Avatar-Skirt-1024"
}

def gen_mesh():
    global LLM
    util.setMode("OBJECT")
    
    if bpy.data.objects.get(LLM.name) != None:
        bpy.data.objects.remove(bpy.data.objects.get(LLM.name))
        
    print(bpy.data.orphans_purge(), "orphans purged")

    bpy.ops.mesh.primitive_vert_add()
    bpy.ops.mesh.delete()

    util.setMode("OBJECT")

    obj = bpy.context.active_object
    obj.data.name = LLM.name
    obj.name = LLM.name
    
    util.setMode("EDIT")

    bm = bmesh.from_edit_mesh(obj.data)
    bm.verts.ensure_lookup_table()
    bm.edges.ensure_lookup_table()
    bm.faces.ensure_lookup_table()

    for v in LLM.verts: bm.verts.new(v)
    bm.verts.index_update()
    bm.verts.ensure_lookup_table()

    for f in LLM.faces: bm.faces.new([bm.verts[i] for i in f])
    bm.faces.index_update()
    bm.faces.ensure_lookup_table()
    
    for i in range(0, LLM.numVerts): bm.verts[i].normal = LLM.norms[i]
    
    bpy.ops.mesh.select_all(action="SELECT")
    bpy.ops.mesh.faces_shade_smooth()

    bm.loops.layers.uv.verify()

    bmesh.update_edit_mesh(obj.data)
    bm.free()

    util.setMode("OBJECT")
    
    for face in obj.data.polygons:
        for vert_idx, loop_idx in zip(face.vertices, face.loop_indices):
            obj.data.uv_layers.active.data[loop_idx].uv = LLM.texCoords[vert_idx]
    
    mat = bpy.data.materials.get(LLM.name)

    if mat is None:
        mat = bpy.data.materials.new(name=LLM.name)
        mat.use_nodes = True

        img = bpy.data.images.get(LLM.name)
        if img is None:
            imgFileName = Name_to_PNG[LLM.name]
            if imgFileName != "":
                filepath = util.path("resources\\" + imgFileName + ".png")
                img = bpy.data.images.load(filepath)
                img.name = LLM.name

        bsdf = mat.node_tree.nodes["Principled BSDF"]

        imgshader = mat.node_tree.nodes.get(LLM.name + "_shader")
        if imgshader is None:
            imgshader = mat.node_tree.nodes.new('ShaderNodeTexImage')
            imgshader.name = LLM.name + "_shader"

        if img is not None: imgshader.image = img
        mat.node_tree.links.new(bsdf.inputs['Base Color'], imgshader.outputs['Color'])

    if obj.data.materials: obj.data.material[0] = mat
    else: obj.data.materials.append(mat)
    
    morph(obj, morphs_to_be_applied)

    return {'FINISHED'}

def morph(obj, morph_selector):
    util.setMode("EDIT")

    bm = bmesh.from_edit_mesh(obj.data)
    bm.verts.ensure_lookup_table()
    bm.edges.ensure_lookup_table()
    bm.faces.ensure_lookup_table()
    
    uvs = {}
    ms = [morph for morph in LLM.morphs if morph[0] in morph_selector]

    for name, vert_morphs in ms:
        print("\tmorphing", name)
        for vix, offset, normal, binormal, texco in vert_morphs:
            bm.verts[vix].co += offset
            uvs[vix] = texco

    bmesh.update_edit_mesh(obj.data)
    bm.free()

    util.setMode("OBJECT")
    
    uv_layer = obj.data.uv_layers.active
    for face in obj.data.polygons:
        for vert_idx, loop_idx in zip(face.vertices, face.loop_indices):
            if uvs.get(vert_idx) is not None:
                #if uvs[vert_idx] != Vector((0,0)): print("\t\t", vert_idx, uvs[vert_idx])
                uv_layer.data[loop_idx].uv += uvs[vert_idx]
    
    return {'FINISHED'}


def load():
    from ossl.formats.format_LLM import Format_LLM
    
    global LLM
    LLM = Format_LLM("upper_body")
    gen_mesh()
    LLM = Format_LLM("lower_body")
    gen_mesh()
    LLM = Format_LLM("head")
    gen_mesh()

    #arm_obj, arm_data, pose = newArmature()

    #skel = loadFileXML("avatar_skeleton.xml")
    #createSkeleton()
    print("\n\nCharacter dummy generation\n", LLM, "\n")

class OSSL_OT_Character_load_Default(bpy.types.Operator):
    """Load Default OSSL Character"""
    bl_label = "OSSL Menu Character Load Default"
    bl_idname = "ossl.character_load_default"
    bl_options = { 'REGISTER' }

    def draw(self, context):
        layout = self.layout

    @classmethod
    def poll(cls, context):
        return True
    
    def execute(self, context):
        load()
        return {'FINISHED'}

def OSSL_operator_Character_load_Default(self, comtext):
    self.layout.operator(OSSL_OT_Character_load_Default.bl_idname, text="default", icon='OUTLINER_DATA_MESH')

import ossl.util as util

def register():
    print("registering: OSSL Type Character Load Default")
    bpy.utils.register_class(OSSL_OT_Character_load_Default)
    bpy.types.OSSL_MT_Character_load.append(OSSL_operator_Character_load_Default)
    print("registered: OSSL Type Character Load Default")

def unregister():
    print("unregistering: OSSL Type Character Load Default")
    bpy.types.OSSL_MT_Character_load.remove(OSSL_operator_Character_load_Default)
    bpy.utils.unregister_class(OSSL_OT_Character_load_Default)
    print("unregistered: OSSL Type Character Load Default")

if __name__ == "__main__":
    import ossl.util as util
    util.reset_addon()
